from django.db import models
from django.utils.translation import gettext_lazy as _
from django.contrib.auth.models import AbstractUser, Group, Permission
from django.core.validators import FileExtensionValidator, MaxValueValidator


class UserType(models.IntegerChoices):
    PERSONAL = 0, _('个人')
    ENTERPRISE = 1, _('企业')


class User(AbstractUser): #Django 内置抽象用户基类，内置用户名和密码的验证
    phone = models.CharField(max_length=11, unique=True, verbose_name="手机号", db_index=True)
    # 邮箱：唯一，用于找回密码/通知，加索引
    email = models.EmailField(max_length=128, unique=True, verbose_name="邮箱", db_index=True)
    # 头像：支持上传，默认图，限制格式（jpg/png）和大小（5MB）
    avatar = models.ImageField(
        upload_to="avatar/",  # 上传文件保存路径（MEDIA_ROOT/avatar/）
        null=True,  # 数据库允许null
        blank=True,  # Admin/表单允许空提交
        verbose_name="头像",  # Admin显示的字段名称
        default="avatar/xx.jpg",  # 默认头像路径（需手动在MEDIA_ROOT/avatar/放xx.jpg）
        validators=[  # 输入验证
            FileExtensionValidator(allowed_extensions=['jpg', 'jpeg', 'png']),  # 仅允许3种图片格式
            MaxValueValidator(5 * 1024 * 1024, message="图片大小不能超过5MB")  # 限制文件大小5MB
        ]
    )
    # 是否启用：默认启用，用于禁用违规用户（软删除替代物理删除）
    is_active = models.BooleanField(default=True, verbose_name="是否启用")
    # 用户类型：关联UserType枚举，默认个人用户，加索引
    user_type = models.PositiveSmallIntegerField(
        choices=UserType.choices,  # 下拉选择框（Admin/表单自动生成）
        default=UserType.PERSONAL,  # 默认值为"个人用户"
        verbose_name="用户类型",
        help_text="0 - 个人，1 - 企业",  # Admin表单提示文本
        db_index=True  # 加索引，提升按用户类型查询的速度
    )
    # 是否认证：关联Authentication模型，活体检测成功（status=4）时自动设为True
    id_verified = models.BooleanField(
        default=False,
        verbose_name="是否认证",
        help_text="关联Authentication模型，liveness_status=4时自动设为True"
    )
    # 创建时间：自动记录用户注册时间（仅首次保存时设置）
    created_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    # 更新时间：自动记录用户信息修改时间（每次保存都更新）
    updated_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")
    # 钉钉OpenID：关联钉钉第三方登录账号，唯一标识
    dingtalk_openid = models.CharField(
        max_length=64,
        null=True,
        blank=True,
        verbose_name="钉钉OpenID",
        db_index=True  # 加索引，提升钉钉登录查询速度
    )
    # 补充字段：预留扩展（如用户等级、所属行业等，暂时未用）
    Suppl_1 = models.CharField(max_length=64, null=True, blank=True, verbose_name="补充字段1")
    Suppl_2 = models.CharField(max_length=64, null=True, blank=True, verbose_name="补充字段2")
    Suppl_3 = models.CharField(max_length=64, null=True, blank=True, verbose_name="补充字段3")
    Suppl_4 = models.CharField(max_length=64, null=True, blank=True, verbose_name="补充字段4")

    # 显式设置groups和user_permissions的related_name（解决继承AbstractUser的冲突）
    groups = models.ManyToManyField(
        Group,
        verbose_name=_('groups'),
        blank=True,
        help_text=_(
            '该用户所属的群组。用户将获得所有权限 '
            '每个组授予的权限'
        ),
        related_name="custom_user_set",  # 自定义反向关联名，避免与其他模型冲突
        related_query_name="user",
    )
    user_permissions = models.ManyToManyField(
        Permission,
        verbose_name=_('user permissions'),
        blank=True,
        help_text=_('用户的权限管理'),
        related_name="custom_user_set",  # 同上，避免冲突
        related_query_name="user",
    )

    # 元数据：控制模型在Admin的显示和数据库表名
    class Meta:
        verbose_name = "用户"  # Admin中单数显示名称
        verbose_name_plural = "用户"  # Admin中复数显示名称
        db_table = "user"  # 数据库表名（默认是app名_模型名，这里自定义为user）

    # 字符串表示：Admin和打印时显示"用户名（手机号）"，方便识别
    def __str__(self):
        return f"{self.username}（{self.phone}）"


# 定义认证状态枚举（整数类型）
class LivenessStatus(models.IntegerChoices):
    UNAUTHENTICATED = 0, _('未认证')  # 未提交任何认证材料
    AUTHENTICATING = 1, _('认证中')  # 已提交材料，正在进行活体检测
    AUTHENTICATING_FAILED = 2, _('认证失败')  # 活体检测未通过
    WAITING_AUDIT = 3, _('待审核')  # 活体检测通过，等待人工审核
    AUTHENTICATING_SUCCESS = 4, _('认证成功')  # 人工审核通过


# 新增证件类型枚举
class CertType(models.IntegerChoices):
    ID_CARD = 0, _('身份证')  # 个人用户
    BUSINESS_LICENSE = 1, _('营业执照')  # 企业用户


# 身份认证模型
class Authentication(models.Model):
    # 与User一对一关联：删除用户时同步删除认证记录
    user = models.OneToOneField(
        User,
        on_delete=models.CASCADE,  # 级联删除（用户删了，认证记录也删）
        verbose_name="用户",
        related_name="authentication",  # 反向关联名（user.authentication可获取认证信息）
        related_query_name="authentication"
    )
    # 证件类型：关联CertType枚举，默认身份证
    cert_type = models.PositiveSmallIntegerField(
        choices=CertType.choices,
        default=CertType.ID_CARD,
        verbose_name="证件类型",
        help_text="选身份证则必填身份证相关字段；选营业执照则必填企业相关字段",
        db_index=True
    )
    # 个人用户字段：身份证姓名（非必填，因企业用户无需）
    id_card_name = models.CharField(max_length=30, null=True, blank=True, verbose_name="身份证姓名")
    # 身份证号：唯一，避免重复认证
    id_card_number = models.CharField(max_length=18, unique=True, null=True, blank=True, verbose_name="身份证号")
    # 企业用户字段：企业名称
    license_company = models.CharField(max_length=64, null=True, blank=True, verbose_name="企业名称")
    # 营业执照号：唯一
    license_number = models.CharField(max_length=18, unique=True, null=True, blank=True, verbose_name="营业执照号")
    # 身份证正面图片：保存路径id_card/
    id_card_front = models.ImageField(upload_to="id_card/", null=True, blank=True, verbose_name="身份证正面")
    # 身份证反面图片
    id_card_back = models.ImageField(upload_to="id_card/", null=True, blank=True, verbose_name="身份证反面")
    # OCR识别结果：存储结构化数据（如姓名、身份证号），默认空字典
    ocr_result = models.JSONField(
        default=dict,
        null=True,
        blank=True,
        verbose_name="OCR识别结果",
        help_text="存储结构化数据，如{'name':'张三','id_card':'123...'}或{'company':'XX公司','license':'456...'}"
    )
    # 活体检测状态：关联LivenessStatus枚举，默认未认证
    liveness_status = models.PositiveSmallIntegerField(
        choices=LivenessStatus.choices,
        default=LivenessStatus.UNAUTHENTICATED,
        verbose_name="活体检测状态",
        help_text="0 - 未认证，1 - 认证中，2 - 认证失败，3 - 待审核，4 - 认证成功",
        db_index=True
    )
    # 活体检测详细结果（如失败原因）
    liveness_result = models.TextField(null=True, blank=True, verbose_name="活体检测结果")
    # 记录创建/更新时间
    created_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    updated_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")
    # 补充字段：预留扩展
    Suppl_1 = models.CharField(max_length=64, null=True, blank=True, verbose_name="补充字段1")
    Suppl_2 = models.CharField(max_length=64, null=True, blank=True, verbose_name="补充字段2")
    Suppl_3 = models.CharField(max_length=64, null=True, blank=True, verbose_name="补充字段3")
    Suppl_4 = models.CharField(max_length=64, null=True, blank=True, verbose_name="补充字段4")

    # 元数据：Admin显示和表名
    class Meta:
        verbose_name = "认证信息"
        verbose_name_plural = "认证信息"
        db_table = "authentication"

    # 属性方法：显式返回关联的User实例，消除代码编辑器类型警告
    @property
    def user_instance(self):
        """显式返回关联的User实例，消除类型警告"""
        return self.user

    # 方法：显式声明choices显示方法，消除未解析警告
    def get_cert_type_display(self) -> str:
        """显式声明Django自动生成的choices显示方法，消除未解析警告"""
        return super().get_cert_type_display()

    # 字符串表示：显示"用户名的认证信息（证件类型）"
    def __str__(self):
        return f"{self.user_instance.username}的认证信息（{self.get_cert_type_display()}）"